Skip to content

Commit

Permalink
Add String>>#localized and String>>#localizedWithAll:
Browse files Browse the repository at this point in the history
Add CurrentLocale dynamic variable
  • Loading branch information
gcotelli committed Jun 19, 2024
1 parent 74f5f3e commit 41cc1f9
Show file tree
Hide file tree
Showing 13 changed files with 375 additions and 7 deletions.
16 changes: 9 additions & 7 deletions source/BaselineOfBuoy/BaselineOfBuoy.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ BaselineOfBuoy >> baselineLocalization: spec [
group: 'Deployment' with: 'Buoy-Localization';
package: 'Buoy-Localization-Extensions' with: [ spec requires: 'Buoy-Localization' ];
group: 'Deployment' with: 'Buoy-Localization-Extensions';
package: 'Buoy-Localization-Pharo-Extensions' with: [ spec requires: 'Buoy-Localization' ];
group: 'Deployment' with: 'Buoy-Localization-Pharo-Extensions';
package: 'Buoy-Localization-Tests'
with: [ spec requires: #( 'Buoy-Localization-Extensions' 'Dependent-SUnit-Extensions' ) ];
group: 'Tests' with: 'Buoy-Localization-Tests'
Expand Down Expand Up @@ -236,13 +238,13 @@ BaselineOfBuoy >> baselineMetaprogramming: spec [
{ #category : 'baselines' }
BaselineOfBuoy >> baselineSUnit: spec [

spec
package: 'Buoy-SUnit-Model';
group: 'Dependent-SUnit-Extensions' with: 'Buoy-SUnit-Model';
package: 'Buoy-SUnit-Pharo-Extensions';
group: 'Dependent-SUnit-Extensions' with: 'Buoy-SUnit-Pharo-Extensions';
package: 'Buoy-SUnit-Tests' with: [ spec requires: 'Dependent-SUnit-Extensions' ];
group: 'Tests' with: 'Buoy-SUnit-Tests'
spec
package: 'Buoy-SUnit-Model' with: [ spec requires: 'Buoy-Localization' ];
group: 'Dependent-SUnit-Extensions' with: 'Buoy-SUnit-Model';
package: 'Buoy-SUnit-Pharo-Extensions';
group: 'Dependent-SUnit-Extensions' with: 'Buoy-SUnit-Pharo-Extensions';
package: 'Buoy-SUnit-Tests' with: [ spec requires: 'Dependent-SUnit-Extensions' ];
group: 'Tests' with: 'Buoy-SUnit-Tests'
]

{ #category : 'baselines' }
Expand Down
12 changes: 12 additions & 0 deletions source/Buoy-Localization-Extensions/String.extension.st
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ String >> escaped [
]
]

{ #category : '*Buoy-Localization-Extensions' }
String >> localized [

^ self localizedWithAll: #( )
]

{ #category : '*Buoy-Localization-Extensions' }
String >> localizedWithAll: collection [

^ NaturalLanguageTranslator current localize: self withAll: collection to: CurrentLocale value
]

{ #category : '*Buoy-Localization-Extensions' }
String >> unescaped [

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"
A NaturalLanguageTranslator is a dummy translator.
The localization framework is found in the gettext package usually
overriding this class completely.
As an alternative you can register a translator using
NaturalLanguageTranslator current: myTranslator
If this is done the messages will be dispatched to it
"
Class {
#name : 'NaturalLanguageTranslator',
#superclass : 'Object',
#classVars : [
'Current'
],
#category : 'Buoy-Localization-GS64-Extensions',
#package : 'Buoy-Localization-GS64-Extensions'
}

{ #category : 'accessing' }
NaturalLanguageTranslator class >> current [
"Return the currently registered translator"

^Current
]

{ #category : 'accessing' }
NaturalLanguageTranslator class >> current: aTranslator [
"Register a translator that should receiver the translation messages"

Current := aTranslator
]
1 change: 1 addition & 0 deletions source/Buoy-Localization-GS64-Extensions/package.st
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Package { #name : 'Buoy-Localization-GS64-Extensions' }
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Extension { #name : 'PolyglotNaturalLanguageTranslator' }

{ #category : '*Buoy-Localization-Pharo-Extensions' }
PolyglotNaturalLanguageTranslator >> translate: string [
"Just for Pharo compatibility"

^ string
]

{ #category : '*Buoy-Localization-Pharo-Extensions' }
PolyglotNaturalLanguageTranslator >> translate: string toLocale: localeID [
"Just for Pharo compatibility"

^ self translate: string
]
1 change: 1 addition & 0 deletions source/Buoy-Localization-Pharo-Extensions/package.st
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Package { #name : 'Buoy-Localization-Pharo-Extensions' }
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"
A PolyglotNaturalLanguageTranslatorTest is a test class for testing the behavior of PolyglotNaturalLanguageTranslator
"
Class {
#name : 'PolyglotNaturalLanguageTranslatorTest',
#superclass : 'TestCase',
#instVars : [
'translator'
],
#category : 'Buoy-Localization-Tests',
#package : 'Buoy-Localization-Tests'
}

{ #category : 'running' }
PolyglotNaturalLanguageTranslatorTest >> setUp [

super setUp.
translator := PolyglotNaturalLanguageTranslator new
]

{ #category : 'tests' }
PolyglotNaturalLanguageTranslatorTest >> testLocalizedToLanguageWithTranslation [

translator
translationFor: 'Happy new year' in: 'es' is: 'Feliz año nuevo';
translationFor: 'Happy new year! \u{1F389}' in: 'es' is: 'Feliz año nuevo! \u{1F389}';
translationFor: 'Happy {1} year' in: 'es' is: 'Feliz año {1}';
translationFor: 'Happy new year! \u{1F389}' in: 'es-AR' is: '¡Feliz año nuevo! \u{1F389}'.

self
assert: ( translator localize: 'Happy new year' to: 'es-AR' ) equals: 'Feliz año nuevo';
assert: ( translator localize: 'Happy new year! \u{1F389}' to: 'es-AR' )
equals: '¡Feliz año nuevo! 🎉';
assert: ( translator localize: 'Happy {1} year' withAll: { 2024 } to: 'es-AR' )
equals: 'Feliz año 2024'.

self
assert: ( translator localize: 'Happy new year' to: 'es' ) equals: 'Feliz año nuevo';
assert: ( translator localize: 'Happy new year! \u{1F389}' to: 'es' )
equals: 'Feliz año nuevo! 🎉';
assert: ( translator localize: 'Happy {1} year' withAll: { 2024 } to: 'es' )
equals: 'Feliz año 2024'.

self
assert: ( translator localize: 'Happy new year' to: 'es-ES' ) equals: 'Feliz año nuevo';
assert: ( translator localize: 'Happy new year! \u{1F389}' to: 'es-ES' )
equals: 'Feliz año nuevo! 🎉';
assert: ( translator localize: 'Happy {1} year' withAll: { 2024 } to: 'es-ES' )
equals: 'Feliz año 2024'
]

{ #category : 'tests' }
PolyglotNaturalLanguageTranslatorTest >> testLocalizedToLanguageWithoutTranslations [

self
assert: ( translator localize: 'Happy new year' to: 'es-AR' ) equals: 'Happy new year';
assert: ( translator localize: 'Happy new year! \u{1F389}' to: 'es-AR' )
equals: 'Happy new year! 🎉';
assert: ( translator localize: 'Happy {1} year' withAll: { 2024 } to: 'es-AR' )
equals: 'Happy 2024 year'
]
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,74 @@ StringLocalizationExtensionsTest >> testEscapedWithoutEscapingSequence [
assert: '¡vamos! ¿adonde?' escaped equals: '¡vamos! ¿adonde?'
]

{ #category : 'tests - localization' }
StringLocalizationExtensionsTest >> testLocalized [

self assert: 'Welcome' localized equals: 'Welcome'.

self
use: [ :translator |
translator
translationFor: 'Welcome' in: 'es' is: 'Bienvenido';
translationFor: 'Welcome'
in: 'ar'
is: '\u{623}\u{647}\u{644}\u{627}\u{64B} \u{648} \u{633}\u{647}\u{644}\u{627}\u{64B}';
translationFor: 'Welcome' in: 'de' is: 'Willkommen';
translationFor: 'Welcome' in: 'fr' is: 'Bienvenue';
translationFor: 'Welcome' in: 'pt' is: 'Bem-vindo';
translationFor: 'Welcome' in: 'ja' is: '\u{3088}\u{3046}\u{3053}\u{305D}'
]
asNaturalLanguageTranslatorDuring: [
self
use: 'es-AR' asLocaleDuring: [ self assert: 'Welcome' localized equals: 'Bienvenido' ];
use: 'es-MX' asLocaleDuring: [ self assert: 'Welcome' localized equals: 'Bienvenido' ];
use: 'ar' asLocaleDuring: [ self assert: 'Welcome' localized equals: 'أهلاً و سهلاً' ];
use: 'de' asLocaleDuring: [ self assert: 'Welcome' localized equals: 'Willkommen' ];
use: 'fr' asLocaleDuring: [ self assert: 'Welcome' localized equals: 'Bienvenue' ];
use: 'pt' asLocaleDuring: [ self assert: 'Welcome' localized equals: 'Bem-vindo' ];
use: 'pt-BR' asLocaleDuring: [ self assert: 'Welcome' localized equals: 'Bem-vindo' ];
use: 'ja' asLocaleDuring: [ self assert: 'Welcome' localized equals: 'ようこそ' ]
]
]

{ #category : 'tests - localization' }
StringLocalizationExtensionsTest >> testLocalizedWithAll [

| stringToTranslate parameters |
stringToTranslate := '{1} seems to be out of sync. Please fetch from "{2}" and try again.'.
parameters := #( 'Buoy' 'origin' ).

self
assert: ( stringToTranslate localizedWithAll: parameters )
equals: 'Buoy seems to be out of sync. Please fetch from "origin" and try again.'.

self
use: [ :translator |
translator
translationFor: stringToTranslate
in: 'es'
is: '{1} parece no estar sincronizado. Por favor, actualiza desde "{2}" y reintenta.';
translationFor: stringToTranslate
in: 'es-AR'
is: '{1} parece no estar sincronizado. Por favor, actualizá desde "{2}" y reintentá.'
]
asNaturalLanguageTranslatorDuring: [
self
use: 'es-AR' asLocaleDuring: [
self
assert: ( stringToTranslate localizedWithAll: parameters )
equals:
'Buoy parece no estar sincronizado. Por favor, actualizá desde "origin" y reintentá.'
];
use: 'es-MX' asLocaleDuring: [
self
assert: ( stringToTranslate localizedWithAll: parameters )
equals:
'Buoy parece no estar sincronizado. Por favor, actualiza desde "origin" y reintenta.'
]
]
]

{ #category : 'tests - escaping' }
StringLocalizationExtensionsTest >> testUnescaped [

Expand Down
18 changes: 18 additions & 0 deletions source/Buoy-Localization/CurrentLocale.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Class {
#name : 'CurrentLocale',
#superclass : 'DynamicVariable',
#category : 'Buoy-Localization',
#package : 'Buoy-Localization'
}

{ #category : 'configuring' }
CurrentLocale class >> use: languageTagOrString during: aBlock [

^ self value: languageTagOrString asLanguageTag during: aBlock
]

{ #category : 'accessing' }
CurrentLocale >> default [

^ 'en' asLanguageTag
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
Class {
#name : 'MonoglotNaturalLanguageTranslator',
#superclass : 'Object',
#instVars : [
'targetLanguageRange',
'translations'
],
#category : 'Buoy-Localization',
#package : 'Buoy-Localization'
}

{ #category : 'instance creation' }
MonoglotNaturalLanguageTranslator class >> for: aLanguageRange [

^ self new initializeFor: aLanguageRange
]

{ #category : 'private' }
MonoglotNaturalLanguageTranslator >> hashCodeFor: string [

^ LanguagePlatform current messageDigest: string
]

{ #category : 'initialization' }
MonoglotNaturalLanguageTranslator >> initializeFor: aLanguageRange [

targetLanguageRange := aLanguageRange.
translations := Dictionary new
]

{ #category : 'testing' }
MonoglotNaturalLanguageTranslator >> isFor: aLanguageRange [

^ targetLanguageRange = aLanguageRange
]

{ #category : 'testing' }
MonoglotNaturalLanguageTranslator >> matches: aLanguageTag [

^ targetLanguageRange matches: aLanguageTag
]

{ #category : 'accessing' }
MonoglotNaturalLanguageTranslator >> specificity [

^targetLanguageRange specificity

]

{ #category : 'private' }
MonoglotNaturalLanguageTranslator >> translationAt: hash put: translatedString [

translations at: hash put: translatedString
]

{ #category : 'configuring' }
MonoglotNaturalLanguageTranslator >> translationFor: string is: translatedString [

^ self translationAt: ( self hashCodeFor: string unescaped ) put: translatedString unescaped
]

{ #category : 'localization' }
MonoglotNaturalLanguageTranslator >> withTranslationOf: string do: block [

translations at: ( self hashCodeFor: string ) ifPresent: block
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
Class {
#name : 'PolyglotNaturalLanguageTranslator',
#superclass : 'Object',
#instVars : [
'translators'
],
#category : 'Buoy-Localization',
#package : 'Buoy-Localization'
}

{ #category : 'class initialization' }
PolyglotNaturalLanguageTranslator class >> initialize [

<ignoreForCoverage>
NaturalLanguageTranslator current: self new
]

{ #category : 'initialization' }
PolyglotNaturalLanguageTranslator >> initialize [

super initialize.
translators := SortedCollection sortBlock: #specificity descending
]

{ #category : 'localization' }
PolyglotNaturalLanguageTranslator >> localize: string to: stringOrLanguageTag [

^ self localize: string withAll: #( ) to: stringOrLanguageTag
]

{ #category : 'localization' }
PolyglotNaturalLanguageTranslator >> localize: string withAll: collection to: stringOrLanguageTag [

| languageTag stringToTranslate |
languageTag := stringOrLanguageTag asLanguageTag.
stringToTranslate := string unescaped.
translators do: [ :translator |
( translator matches: languageTag ) then: [
translator
withTranslationOf: stringToTranslate
do: [ :translatedString | ^ translatedString format: collection ]
]
].
^ stringToTranslate format: collection
]

{ #category : 'configuring' }
PolyglotNaturalLanguageTranslator >> translationFor: string in: targetLanguageRange is: translatedString [

^ ( self translatorFor: targetLanguageRange ) translationFor: string is: translatedString
]

{ #category : 'private' }
PolyglotNaturalLanguageTranslator >> translatorFor: stringOrLanguageRange [

| range |
range := stringOrLanguageRange asLanguageRange.

^ translators
detect: [ :translator | translator isFor: range ]
ifNone: [ translators add: ( MonoglotNaturalLanguageTranslator for: range ) ]
]
Loading

0 comments on commit 41cc1f9

Please sign in to comment.