{
"asset": {
"attachDoc(context=TaskType, param=attachDoc)": {
"calibrationGroup": "You can attach up to 5 documents to calibration tasks.",
"maintenanceGroup": "You can attach up to 5 documents to maintenance tasks.",
"retirement, breakdown, maintenance,calibration": "---"
},
"bulk": {
"changeStatus": "Change <b>Status</b> of selected tasks",
"editAssignment": "Edit <b>Assignment</b> of selected tasks",
"expiryDate": "Set <b>Expiry Date</b> of selected tasks",
"uplaodDocument": "Upload <b>Document</b> to selected tasks"
},
"calibrationGroupAttachUpToFiveDoc": "You can attach up to 5 documents to calibration tasks.",
"calibrationGroupCheckDocsAlreadyAttached": "Please check the documents already attached to the calibration tasks you selected.",
"checkDocsAlreadyAttached(context=TaskType, param=checkDocsAlreadyAttached)": {
"calibrationGroup": "Please check the documents already attached to the calibration tasks you selected.",
"maintenanceGroup": "Please check the documents already attached to the maintenance tasks you selected.",
"retirement, breakdown, maintenance,calibration": "---"
},
"detail(context=TaskType, param=detail)": {
"calibration": "Planned Calibration",
"maintenance": "Planned Maintenance",
"retirement, breakdown, maintenanceGroup,calibrationGroup": "---"
}
}
}
tr:
{
"asset": {
"attachDoc(context=TaskType, param=attachDoc)": {
"calibrationGroup": "Kalibrasyon görevlerine en fazla 5 belge ekleyebilirsiniz.",
"maintenanceGroup": "Bakım görevlerine en fazla 5 belge ekleyebilirsiniz.",
"retirement, breakdown, maintenance,calibration": "---"
},
"bulk": {
"changeStatus": "Seçili görevlerin <b>Durumunu</b> değiştir",
"editAssignment": "Seçilen görevlerin <b>Atamasını</b> düzenle",
"expiryDate": "Seçili görevlerin <b>Bitiş Tarihini</b> ayarla",
"uplaodDocument": "Seçili görevlere <b>Belge</b> yükle"
},
"calibrationGroupAttachUpToFiveDoc": "Kalibrasyon görevlerine en fazla 5 belge ekleyebilirsiniz.",
"calibrationGroupCheckDocsAlreadyAttached": "Lütfen seçtiğiniz kalibrasyon görevlerine eklenmiş olan belgeleri kontrol edin.",
"checkDocsAlreadyAttached(context=TaskType, param=checkDocsAlreadyAttached)": {
"calibrationGroup": "Lütfen seçtiğiniz kalibrasyon görevlerine eklenmiş olan belgeleri kontrol edin.",
"maintenanceGroup": "Lütfen seçtiğiniz bakım görevlerine eklenmiş olan belgeleri kontrol edin.",
"retirement, breakdown, maintenance,calibration": "---"
},
"detail(context=TaskType, param=detail)": {
"calibration": "Planlı Kalibrasyon",
"maintenance": "Planlı Bakım",
"retirement, breakdown, maintenanceGroup,calibrationGroup": "---"
}
}
}
ro:
{
"asset": {
"attachDoc(context=TaskType, param=attachDoc)": {
"calibrationGroup": "Poti adauga maxim 5 documente pentru calibrari.",
"maintenanceGroup": "Ati atins limita de 5 documente. Daca doriti sa adaugati alte documente puteti sterge din cele existente.",
"retirement, breakdown, maintenance,calibration": "---"
},
"bulk": {
"changeStatus": "Schimba <b>Statusul</b> sarcinii de lucru selectate.",
"editAssignment": "Editati <b> Atribuirea </b> la sarcinilor de lucru selectate.",
"expiryDate": "Setati <b>Data de expirare</b> a sarcinii de lucru selectate.",
"uplaodDocument": "Incarcati <b>un document </b> la sarcina de lucru selectata."
},
"calibrationGroupAttachUpToFiveDoc": "Poti adauga maxim 5 documente pentru calibrari.",
"calibrationGroupCheckDocsAlreadyAttached": "Va rugam sa verificati documentele deja introduse.",
"checkDocsAlreadyAttached(context=TaskType, param=checkDocsAlreadyAttached)": {
"calibrationGroup": "Please check the documents already attached to the calibration tasks you selected.",
"maintenanceGroup": "Please check the documents already attached to the maintenance tasks you selected.",
"retirement, breakdown, maintenance,calibration": "---"
},
"detail(context=TaskType, param=detail)": {
"calibration": "Calibrare planificata",
"maintenance": "Mentenanta Planificata",
"retirement, breakdown, maintenanceGroup,calibrationGroup": "---"
}
}
}
Create the enum file: touch lib/task_type_enum.dart
(base) en -> lib/translations/strings_en.i18n.json
ro -> lib/translations/strings_ro.i18n.json
tr -> lib/translations/strings_tr.i18n.json
Unhandled exception:
Null check operator used on a null value
#17 main (file:///home/talha/.pub-cache/hosted/pub.dev/slang-3.31.2/bin/slang.dart:142:7)
```
**Expected behavior**
Generator should generate translations without any error.
**Additional context**
Works fine when `fallback_strategy` set to `none`
Before upgrading the package to latest version, i had the following versions and it was working fine:
```
slang: ^3.28.0
slang_flutter: ^3.23.0
build_runner: ^2.4.6
slang_build_runner: ^3.23.0
```
In past, we opened this issue: [issue](https://github.com/slang-i18n/slang/issues/182)
We saw your comment saying that the said the problem was solved, so we decided to update slang to latest version and encountered this problem.
And at that time, we created the following script which solved our problem:
```python
import json
import os
import shutil
import subprocess
def read_translation_data(lang, translation_files_path):
file_path = os.path.join(translation_files_path, f"strings_{lang}.i18n.json")
with open(file_path, 'r', encoding='utf-8') as translation_file:
return json.load(translation_file)
def write_translation_data(lang, translation_data, translation_files_path):
file_path = os.path.join(translation_files_path, f"strings_{lang}.i18n.json")
with open(file_path, 'w', encoding='utf-8') as translation_file:
json.dump(translation_data, translation_file, ensure_ascii=False, indent=2, sort_keys=True)
def update_translations(reference_lang, translations_path):
reference_data = read_translation_data(reference_lang, translations_path)
for lang in ['tr', 'ro']:
translation_data = read_translation_data(lang, translations_path)
add_missing_keys(lang, reference_data, translation_data)
create_temp_file(lang, translations_path)
fill_empty_keys_with_english(reference_data, translation_data)
with open(os.path.join(translations_path, f"strings_{lang}.i18n.json"), 'w', encoding='utf-8') as updated_translation_file:
json.dump(translation_data, updated_translation_file, ensure_ascii=False, indent=2, sort_keys=True)
def create_temp_file(lang, translations_path):
temp_translation_file_path = os.path.join(translations_path, f"temp_strings_{lang}.i18n.json")
shutil.copy(os.path.join(translations_path, f"strings_{lang}.i18n.json"), temp_translation_file_path)
def add_missing_keys(lang, reference, translation):
for key, value in reference.items():
if isinstance(value, dict):
if key not in translation:
translation[key] = {}
add_missing_keys(lang, value, translation[key])
else:
if key not in translation:
translation[key] = ""
write_translation_data(lang, translation, translations_path)
def fill_empty_keys_with_english(reference, translation):
for key, value in reference.items():
if isinstance(value, dict):
fill_empty_keys_with_english(value, translation[key])
elif key in translation and not translation[key]:
translation[key] = value
def sort_translation_data(translation_data):
for key, value in translation_data.items():
if isinstance(value, dict):
translation_data[key] = sort_translation_data(value)
return dict(sorted(translation_data.items()))
def remove_unused_keys_recursive(reference, translation):
for key in list(translation.keys()):
if key not in reference:
del translation[key]
elif isinstance(reference[key], dict) and isinstance(translation[key], dict):
remove_unused_keys_recursive(reference[key], translation[key])
def remove_unused_keys(reference_lang, translations_path):
reference_data = read_translation_data(reference_lang, translations_path)
for lang in ['tr', 'ro']:
translation_data = read_translation_data(lang, translations_path)
remove_unused_keys_recursive(reference_data, translation_data)
write_translation_data(lang, translation_data, translations_path)
if __name__ == "__main__":
reference_language = "en"
translations_path = "lib/translations"
print("\n###############################################\n")
print("Translations is starting to update...")
print("Checking for missing and empty values")
update_translations(reference_language, translations_path)
# Run the dart command after processing all language files
print("json files are ready to generate dart files!")
print("Running dart command...")
subprocess.run([ "dart", "run", "slang"])
enPath = "strings_en.i18n.json"
trPath = "strings_tr.i18n.json"
roPath = "strings_ro.i18n.json"
# Değişiklik yapılacak dosyaları belirle
files_to_change = [trPath, roPath]
# Dosyaları değiştir
for lang_file in files_to_change:
lang = lang_file.split('_')[1].split('.')[0] # Dosya adından dil bilgisini çıkar
temp_file_path = os.path.join(translations_path, f"temp_{lang_file}")
original_file_path = os.path.join(translations_path, lang_file)
shutil.move(temp_file_path, original_file_path)
# İngilizce haricindeki dillerin kullanılmayan key'leri sil
remove_unused_keys(reference_language, translations_path)
# En dosyasını sırala ve güncelle
en_data = read_translation_data("en", translations_path)
en_data_sorted = sort_translation_data(en_data)
write_translation_data("en", en_data_sorted, translations_path)
print("JSON files updated successfully.")
print("SUCCESS!")
print("\n###############################################\n")
```
What changes have been made and what/how should we implement it? I would be happy if you can navigate me to find out whats the problem.
Describe the bug Cannot generate translations when
fallback_strategy
set tobase_locale_empty_string
To Reproduce Steps to reproduce the behavior:
flutter create slang_test
mkdir lib/translations
en:
tr:
ro:
touch lib/task_type_enum.dart
targets: $default: builders: slang_build_runner: options: input_directory: lib/translations output_directory: lib/translations translate_var: t fallback_strategy: base_locale_empty_string string_interpolation: braces imports:
'package:slang_test/task_type_enum.dart'
freezed: options: maybe_when: false maybe_map: false
Generating translations...
Found build.yaml!
-> fileType: json -> baseLocale: en -> fallbackStrategy: baseLocaleEmptyString -> inputDirectory: lib/translations -> inputFilePattern: .i18n.json -> outputDirectory: lib/translations -> outputFileName: strings.g.dart -> outputFileFormat: singleFile -> localeHandling: true -> flutterIntegration: true -> namespaces: false -> translateVar: t -> enumName: AppLocale -> translationClassVisibility: private -> keyCase: null (no change) -> keyCase (for maps): null (no change) -> paramCase: null (no change) -> stringInterpolation: braces -> renderFlatMap: true -> translationOverrides: false -> renderTimestamp: true -> renderStatistics: true -> maps: [] -> pluralization/auto: cardinal -> pluralization/default_parameter: n -> pluralization/cardinal: [] -> pluralization/ordinal: [] -> contexts:
Scanning translations...
(base) en -> lib/translations/strings_en.i18n.json ro -> lib/translations/strings_ro.i18n.json tr -> lib/translations/strings_tr.i18n.json Unhandled exception: Null check operator used on a null value
0 _digestContextEntries (package:slang/builder/builder/translation_model_builder.dart:855:62)
1 _parseMapNode. (package:slang/builder/builder/translation_model_builder.dart:416:31)
2 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:633:13)
3 _parseMapNode (package:slang/builder/builder/translation_model_builder.dart:236:8)
4 _parseMapNode. (package:slang/builder/builder/translation_model_builder.dart:320:20)
5 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:633:13)
6 _parseMapNode (package:slang/builder/builder/translation_model_builder.dart:236:8)
7 TranslationModelBuilder.build (package:slang/builder/builder/translation_model_builder.dart:78:28)
8 TranslationModelListBuilder.build. (package:slang/builder/builder/translation_model_list_builder.dart:47:48)
9 MappedIterator.moveNext (dart:_internal/iterable.dart:403:20)
10 new _GrowableList._ofOther (dart:core-patch/growable_array.dart:202:26)
11 new _GrowableList.of (dart:core-patch/growable_array.dart:152:26)
12 new List.of (dart:core-patch/array_patch.dart:39:18)
13 Iterable.toList (dart:core/iterable.dart:498:7)
14 TranslationModelListBuilder.build (package:slang/builder/builder/translation_model_list_builder.dart:62:8)
15 GeneratorFacade.generate (package:slang/src/builder/generator_facade.dart:19:62)
16 generateTranslations (file:///home/talha/.pub-cache/hosted/pub.dev/slang-3.31.2/bin/slang.dart:318:34)