->using(TechniqueChapter::class);
}
+ public function translations() {
+ return $this->hasMany(TechniqueTranslation::class);
+ }
+
protected $casts = [
'index' => 'boolean',
];
+
+ protected $with = [
+ 'translations',
+ ];
+
}
--- /dev/null
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class TechniqueTranslation extends Model
+{
+ use HasFactory;
+}
--- /dev/null
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+ /**
+ * Run the migrations.
+ *
+ * @return void
+ */
+ public function up()
+ {
+ Schema::create('technique_translations', function (Blueprint $table) {
+ $table->id();
+ $table->foreignId('technique_id')->constrained();
+ $table->string('locale');
+ $table->text('title');
+ $table->text('short');
+ $table->text('description');
+ $table->timestamps();
+ $table->unique(['technique_id', 'locale']);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('technique_translations');
+ }
+};
import PropTypes from 'prop-types';
import React from 'react';
import { Container } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
import Outline from './Outline';
+import { getTranslation } from '../../helpers/Technique';
+import i18n from '../../i18n';
const Detail = ({ technique }) => <Container as="article">
- <h1>{technique.title}</h1>
+ <h1>{getTranslation(technique, 'title', i18n.language)}</h1>
<Outline technique={technique} />
- <div dangerouslySetInnerHTML={{ __html: technique.description }} />
+ <div dangerouslySetInnerHTML={{
+ __html: getTranslation(technique, 'description', i18n.language),
+ }} />
{technique.chapters ? technique.chapters.map(chapter =>
<section id={`c${chapter.id}`} key={`c${chapter.id}`}>
{chapter.pivot.level ?
- React.createElement(`h${chapter.pivot.level}`, {}, chapter.title)
+ React.createElement(
+ `h${chapter.pivot.level}`,
+ {},
+ getTranslation(chapter, 'title', i18n.language),
+ )
: null}
- <div dangerouslySetInnerHTML={{ __html: chapter.description }} />
+ <div dangerouslySetInnerHTML={{
+ __html: getTranslation(chapter, 'description', i18n.language),
+ }} />
</section>
) : null}
</Container>;
}),
};
-export default Detail;
+export default withTranslation()(Detail);
import PropTypes from 'prop-types';
import React from 'react';
import { ListGroup } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import { getTranslation } from '../../helpers/Technique';
+import i18n from '../../i18n';
const Outline = ({ technique }) => technique.chapters && technique.chapters.length ?
<aside className="tech-outline mb-3 ms-3">
action
href={`#c${chapter.id}`}
key={`c${chapter.id}`}
- title={chapter.short || null}
+ title={getTranslation(chapter, 'short', i18n.language) || null}
>
- {chapter.title}
+ {getTranslation(chapter, 'title', i18n.language)}
</ListGroup.Item>
: null)}
</ListGroup>
}),
};
-export default Outline;
+export default withTranslation()(Outline);
--- /dev/null
+export const getTranslation = (tech, prop, lang) => {
+ const direct = tech.translations.find(t => t.locale === lang);
+ if (direct) {
+ return direct[prop];
+ }
+ const sameLang = tech.translations.find(t => t.locale.substr(0, 2) === lang.substr(0, 2));
+ if (sameLang) {
+ return sameLang[prop];
+ }
+ return tech[prop];
+};
+
+export default {
+ getTranslation,
+};